﻿using Nemerle.Collections;
using Nemerle.Peg;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

namespace Nemerle2.Compiler
{
  /*
  declarations:
   alias      = attributes? modifiers?            "type"      identifier type-parameter-list? "=" class-type;
   class      = attributes? modifiers? "partial"? "class"     identifier type-parameter-list? class-base?                    type-parameter-constraints-clauses? body ";"?
   struct     = attributes? modifiers? "partial"? "struct"    identifier type-parameter-list? struct-interfaces?             type-parameter-constraints-clauses? body ";"?
   interface  = attributes? modifiers? "partial"? "interface" identifier type-parameter-list? interface-base?                type-parameter-constraints-clauses? body ";"?
   delegate   = attributes? modifiers?            "delegate"  identifier type-parameter-list? "(" formal-parameter-list? ")" type-parameter-constraints-clauses?      ";"
   enum       = attributes? modifiers?            "enum"      identifier                      enum-base?                                                         body ";"?
  */

  /// <summary>
  /// AST of types.
  /// </summary>
  [Record]
  public variant PTypeDeclaration : PDeclarationBase
  {
    | Alias         { TypeParameters : PTypeParameters; Type    : PExpr; }
    | Class         { TypeParameters : PTypeParameters; Constraints : PConstraints; Parents : LocatedList[PExpr]; Members : LocatedList[PMember]; }
    | Interface     { TypeParameters : PTypeParameters; Constraints : PConstraints; Parents : LocatedList[PExpr]; Members : LocatedList[PMember]; }
    | Struct        { TypeParameters : PTypeParameters; Constraints : PConstraints; Parents : LocatedList[PExpr]; Members : LocatedList[PMember]; }
    | Variant       { TypeParameters : PTypeParameters; Constraints : PConstraints; Parents : LocatedList[PExpr]; Members : LocatedList[PMember]; }
    | VariantOption {                                                               Parents : LocatedList[PExpr]; Members : LocatedList[PMember]; }
    | Delegate      { TypeParameters : PTypeParameters; Header  : PFunHeader; }
    | Enum          {                                   Extend  : PExpr;                                          Members : LocatedList[PMember]; }
    | Expr          { Code    : PExpr; }
    | Error         { Msg     : Msg; }

    | MacroClass    { Members : LocatedList[PMember]; }

    public HeaderLocation : Location;

    public GetMembers() : ValueOption[LocatedList[PMember]]
    {
      match(this)
      {
        | Class(_, _, _, members)
        | Struct(_, _, _, members)
        | Interface(_, _, _, members)
        | Variant(_, _, _, members)
        | VariantOption(_, members) =>
          ValueOption.Some(members)

        | Alias
        | Delegate
        | Enum
        | Expr
        | MacroClass
        | Error =>
          ValueOption.None()
      }
    }

    public override ToString() : string
    {
      match(this)
      {
        | Alias(parms, t)                 => $<#type $Name[$parms] = $t#>
        | Class(parms, _, parents, _)     => $<#class $Name[$parms]: ..$(parents; ", ")#>
        | Struct(parms, _, parents, _)    => $<#struct $Name[$parms]: ..$(parents; ", ")#>
        | Interface(parms, _, parents, _) => $<#interface $Name[$parms]: ..$(parents; ", ")#>
        | Variant(parms, _, parents, _)   => $<#variant $Name[$parms]: ..$(parents; ", ")#>
        | VariantOption(parents, _)       => $<#| $Name : ..$(parents; ", ")#>
        | Delegate(parms, header)         => $<#delegate $Name[$parms]$header#>
        | Enum(extends, _)                => $<#enum $Name: $extends#>
        | Expr(code)                      => code.ToString()
        | MacroClass(_)                   => $<#macro class $Name#>
        | Error(msg)                      => $<#ERROR: $msg#>
      }
    }
  }
}
